package com.jichangxiu.system.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.jichangxiu.common.annotation.Dynamic;
import com.jichangxiu.common.annotation.Scope;
import com.jichangxiu.common.entity.bo.JcxContextEntity;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.utils.ConvertUtils;
import com.jichangxiu.common.entity.rule.InfoRule;
import com.jichangxiu.framework.service.impl.BaseServiceImpl;
import com.jichangxiu.framework.utils.DynamicUtils;
import com.jichangxiu.framework.utils.NoUtils;
import com.jichangxiu.framework.utils.SecurityUtils;
import com.jichangxiu.system.entity.bo.SysInfoBo;
import com.jichangxiu.system.entity.dto.edit.EditSysInfo;
import com.jichangxiu.system.entity.dto.query.QuerySysInfo;
import com.jichangxiu.system.entity.po.SysInfo;
import com.jichangxiu.system.entity.po.SysUser;
import com.jichangxiu.system.entity.vo.SysInfoVo;
import com.jichangxiu.system.mapper.SysInfoMapper;
import com.jichangxiu.system.service.SysInfoService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotBlank;
import java.util.List;

/**
 * SysInfoServiceImpl:
 *
 * @author JiChangXiu
 * @create 2024-06-28 13:44:24
 */
@Service
public class SysInfoServiceImpl extends BaseServiceImpl<SysInfoMapper, SysInfo, SysInfoVo> implements SysInfoService {

    /**
     * 保存登录、登出信息
     *
     * @param jcxContextEntity 上下文实体
     * @param infoRule         登录、登出信息
     */
    @Override
    public void saveInfoRule(JcxContextEntity jcxContextEntity, InfoRule infoRule) {
        DynamicUtils.changeSource(jcxContextEntity.getTenantSource());
        SysInfo sysInfo = SysInfo.builder()
                .id(IdWorker.getIdStr())
                .no(NoUtils.createNo(jcxContextEntity.getTenantId(), "login"))
                .tenantId(jcxContextEntity.getTenantId())
                .userId(infoRule.getUserId())
                .type(infoRule.getType())
                .address(infoRule.getAddress())
                .location(infoRule.getLocation())
                .browser(infoRule.getBrowser())
                .system(infoRule.getSystem())
                .param(infoRule.getParam())
                .result(infoRule.getResult())
                .exception(infoRule.getException())
                .status(infoRule.getStatus())
                .jti(infoRule.getJti())
                .jwt(infoRule.getJwt())
                .build();
        sysInfo.setDeptBy(jcxContextEntity.getDeptId());
        sysInfo.setCreateBy(jcxContextEntity.getUserId());
        sysInfo.setUpdateBy(jcxContextEntity.getUserId());
        getBaseMapper().insert(sysInfo);
        DynamicUtils.resetSource();
    }

    /**
     * 修改系统登录信息
     *
     * @param editSysInfo 修改系统登录信息视图对象
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean edit(EditSysInfo editSysInfo) {
        return getBaseMapper().updateById(addAndEditValidBo(ConvertUtils.convert(editSysInfo, SysInfoBo.class))) > 0;
    }

    /**
     * 根据主键查询系统登录信息
     *
     * @param id       系统登录信息主键
     * @param isExtend 是否扩展
     * @return 系统登录信息详情
     */
    @Dynamic
    @Override
    public SysInfoVo info(@NotBlank(message = "主键不能为空") String id, Boolean isExtend) {
        SysInfoVo sysInfoVo = getBaseMapper().selectJoinOne(SysInfoVo.class, buildQueryWrapper(QuerySysInfo.builder().id(id).build()));
        if (Boolean.TRUE.equals(isExtend) && ObjectUtil.isNotEmpty(sysInfoVo))
            sysInfoVo = renderSysInfoVoList(ListUtil.toList(sysInfoVo)).get(0);
        return sysInfoVo;
    }

    /**
     * （可分页）查询系统登录信息列表
     *
     * @param querySysInfo 查询视图对象
     * @return （分页）系统登录信息列表
     */
    @Scope
    @Dynamic
    @Override
    public Page<SysInfoVo> lists(QuerySysInfo querySysInfo) {
        Page<SysInfoVo> sysInfoVoPage = getBaseMapper().selectJoinPage(startPage(), SysInfoVo.class, buildQueryWrapper(querySysInfo));
        if (Boolean.TRUE.equals(querySysInfo.getIsExtend()))
            sysInfoVoPage.setRecords(renderSysInfoVoList(sysInfoVoPage.getRecords()));
        return sysInfoVoPage;
    }

    /**
     * 新增 / 修改 前校验
     *
     * @param sysInfoBo 校验用业务对象
     * @return 数据库操作对象
     */
    private SysInfo addAndEditValidBo(SysInfoBo sysInfoBo) {
        SysInfo sysInfo = ConvertUtils.convert(sysInfoBo, SysInfo.class);
        if (ObjectUtil.isNull(sysInfo))
            throw new ServiceException("待校验对象为空");
        if (StrUtil.isEmpty(sysInfo.getId())) {
            // 新增
            sysInfo.setTenantId(SecurityUtils.getTenantId());
            return sysInfo;
        } else {
            // 修改
            SysInfo dbSysInfo = getById(sysInfo.getId());
            dbSysInfo.setRemark(sysInfo.getRemark());
            return dbSysInfo;
        }
    }

    /**
     * 渲染视图
     *
     * @param sysInfoVoList 视图列表
     * @return 渲染后的视图列表
     */
    private List<SysInfoVo> renderSysInfoVoList(List<SysInfoVo> sysInfoVoList) {
        if (ObjectUtil.isNotEmpty(sysInfoVoList)) {
            // todo 扩展信息填入
        }
        return sysInfoVoList;
    }

    /**
     * 构建查询条件
     *
     * @param querySysInfo 查询用业务对象
     * @return 查询条件
     */
    private MPJLambdaWrapper<SysInfo> buildQueryWrapper(QuerySysInfo querySysInfo) {
        MPJLambdaWrapper<SysInfo> lambdaQueryWrapper = new MPJLambdaWrapper<SysInfo>()
                .selectAll(SysInfo.class)
                .leftJoin(SysUser.class, SysUser::getId, SysInfo::getUserId, ext -> ext
                        .selectAs(SysUser::getName, SysInfoVo::getUserName))
                .disableSubLogicDel();
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getId()), SysInfo::getId, querySysInfo.getId());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getNo()), SysInfo::getNo, querySysInfo.getNo());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getType()), SysInfo::getType, querySysInfo.getType());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getAddress()), SysInfo::getAddress, querySysInfo.getAddress());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getLocation()), SysInfo::getLocation, querySysInfo.getLocation());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getBrowser()), SysInfo::getBrowser, querySysInfo.getBrowser());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getSystem()), SysInfo::getSystem, querySysInfo.getSystem());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getParam()), SysInfo::getParam, querySysInfo.getParam());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getResult()), SysInfo::getResult, querySysInfo.getResult());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getException()), SysInfo::getException, querySysInfo.getException());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysInfo.getStatus()), SysInfo::getStatus, querySysInfo.getStatus());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getJti()), SysInfo::getJti, querySysInfo.getJti());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getJwt()), SysInfo::getJwt, querySysInfo.getJwt());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysInfo.getUserId()), SysInfo::getUserId, querySysInfo.getUserId());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysInfo.getRemark()), SysInfo::getRemark, querySysInfo.getRemark());
        lambdaQueryWrapper.apply(StrUtil.isNotEmpty(querySysInfo.getScope()), querySysInfo.getScope());
        lambdaQueryWrapper.orderByAsc(SysInfo::getCreateTime);
        return lambdaQueryWrapper;
    }

}